﻿using System;
using netDxf;
using netDxf.Entities;

namespace TestDxfDocument
{
    class RectShank
    {
        private static readonly double pi = Math.PI;

        #region 私有字段
        private double b;
        private double h2;
        private double h1;
        private double l1;
        private double l2;
        private double f;
        private double lfa;
        private double l3;
        private bool isTf;
        private int insertShape;
        private double lambdas;//刃倾角
        private double gammao;//前角或法前角
        private bool o7n;
        private double alphan;
        private double cutagl;
        private double insertagl;
        private double repsilon;
        private double s;
        #endregion

        #region 构造器
        public RectShank(double b, double h2, double h1, double l1, double l2, double f, double lfa, double l3, bool isTf, double cutagl, double insertagl, int insertShape, double lambdas, bool o7n, double gammao, double alphan, double s, double repsilon)
        {

            if (s <= 0)
            {
                throw new Exception("刀片厚度s=" + b + ",s不能小于0");
            }
            else
            {
                this.s = s;
            }
            if (b <= 0)
            {
                throw new Exception("刀杆宽度b="+ b +",b不能小于0");
            }
            else
            {
                this.b = b;
            }
            if (h2 <= 0)
            {
                throw new Exception("刀杆高度h2="+ h2 +",h2不能小于0");
            }
            else
            {
                this.h2 = h2;
            }
            if (h1 <= 0)
            {
                throw new Exception("刀杆高度h1=" + h1 + ",h1不能小于0");
            }
            else
            {
                this.h1 = h1;
            }

            if (l1 <= 0)
            {
                throw new Exception("刀杆高度l1=" + l1 + ",l1不能小于0");
            }
            else
            {
                this.l1 = l1;
            }
            if (l2 <= 0)
            {
                throw new Exception("刀杆高度l2=" + l2 + ",l2不能小于0");
            }
            else
            {
                this.l2 = l2;
            }
            if (lfa <= 0)
            {
                throw new Exception("刀杆高度lfa=" + lfa + ",lfa不能小于0");
            }
            else if (lfa.Equals(double.NaN))
            {
                lfa = 0;
            }
            else
            {
                this.lfa = lfa;
            }

            if (l3 <= 0)
            {
                throw new Exception("刀杆高度l3=" + l3 + ",l3不能小于0");
            }
            else
            {
                this.l3 = l3;
            }

            if (cutagl <= 0)
            {
                throw new Exception("主偏角cutagl=" + cutagl + ",cutagl不能小于0");
            }
            else
            {
                this.cutagl = cutagl;
            }

            if (insertagl <= 0)
            {
                throw new Exception("主偏角insertagl=" + insertagl + ",insertagl不能小于0");
            }
            else
            {
                this.insertagl = insertagl;
            }

            if (f <= 0)
            {
                throw new Exception("功能宽度f=" + f + ",f不能小于0");
            }
            else
            {
                this.f = f;
            }

            if (repsilon <= 0)
            {
                repsilon = 0.001;
            }
            else
            {
                this.repsilon = repsilon;
            }

            this.o7n = o7n;
            this.isTf = isTf;
            this.insertShape = insertShape;
            this.lambdas = lambdas;
            this.gammao = gammao;
            this.alphan = alphan;
        }

        public RectShank(double b, double l1, double f, double l2,double l3,double lfa, int insertShape,bool isTf, double cutagl, double insertagl,double lambdas,bool o7n,double gammao,double alphan,double s, double repsilon)
        :this(b,  b,  b,  l1,  l2,  f,  lfa,  l3,  isTf,  cutagl, insertagl, insertShape,  lambdas,  o7n, gammao,  alphan,  s, repsilon)
        {

        }

        public RectShank(double b, double l1, double f, double l2, double l3, int insertShape, bool isTf, double insertagl,double cutagl,double lambdas, bool o7n, double gammao, double alphan, double s, double repsilon)
        : this(b, l1, f, l2, l3, double.NaN, insertShape, isTf, cutagl, insertagl, lambdas, o7n, gammao, alphan, s,repsilon)
        {

        }
        #endregion

        #region 获取属性
        public double B { get => b; }
        public double H2 { get => h2; }
        public double H1 { get => h1; }
        public double L1 { get => l1; }
        public double L2 { get => l2; }
        public double F { get => f; }
        public double Lfa { get => lfa; }
        public double L3 { get => l3; }
        public bool IsTf { get => isTf; }
        public int InsertShape { get => insertShape; }
        public double Lambdas { get => lambdas; }
        public bool O7n { get => o7n; }
        public double Gammao { get => gammao; }
        public double Alphan { get => alphan; }
        public double Cutagl { get => cutagl; }
        public double Insertagl { get => insertagl; }
        public double Repsilon { get => repsilon; }
        public double S { get => s; }
        #endregion

        #region
        public Vector3[] Inserts
        {
            get {
                Vector2 icorner;
                if (cutagl <= pi / 2 && !isTf)//纵向进给，kapr小于等于90°
                {
                    icorner = fun.Polar(Vector2.Zero, -cutagl, repsilon * (1 / Math.Tan(insertagl / 2) - 1 / Math.Tan((pi - cutagl) / 2)));
                }
                else if (cutagl <= pi / 2 && isTf)//横向进给，kapr小于等于90°
                {
                    icorner = fun.Polar(Vector2.Zero, cutagl + pi / 2, repsilon / Math.Tan(insertagl / 2) - repsilon / Math.Tan((pi - cutagl) / 2));
                }
                else if (cutagl > pi / 2 && IsTf)//横向进给，kapr大于90
                {
                    Vector2 cen = fun.Polar(Vector2.Zero, pi / 4, repsilon / Math.Sin(pi / 4));
                    icorner = fun.Polar(cen, -3 * pi / 2 + cutagl + insertagl / 2, repsilon / Math.Sin(insertagl / 2));
                }
                else//纵向进给，kapr大于90
                {
                    Vector2 cen = fun.Polar(Vector2.Zero, pi / 4, repsilon / Math.Sin(pi / 4));
                    icorner = fun.Polar(cen, insertagl / 2 - cutagl + 3 * pi / 2, repsilon / Math.Cos(insertagl / 2));
                }

                //刀片的上表面
                Vector2[] inserts2d;
                if (InsertShape == 6)
                {
                    inserts2d = Pus.Hexagonal(icorner, l3, insertagl, cutagl, isTf);
                }
                else if (InsertShape == 3)
                {
                    inserts2d = Pus.TrianglePoints(icorner, l3, isTf, cutagl);
                }
                else
                {
                    inserts2d = Pus.DiamondPoints(icorner, l3, insertagl, isTf, cutagl);
                }
                double insertOffset = Math.Tan(alphan) * s;
                //刀片下表面
                Vector2[] inserts2dd = Pus.OffsetPoints(insertOffset, inserts2d);
                //刀片模型
                Vector3[] inserts = new Vector3[inserts2d.Length * 2];
                for (int i = 0; i < inserts2d.Length; i++)
                {
                    inserts[i] = Pus.ToV3(inserts2dd[i], Vector3.Zero.Z - S);
                    inserts[i + inserts2d.Length] = Pus.ToV3(inserts2d[i], Vector3.Zero.Z);
                }

                //放倒
                Vector3 laydownV = new Vector3(-1, 0, 0);
                double laydownR = pi / 2;
                for (int i = 0; i < inserts.Length; i++)
                {
                    inserts[i] = Pus.Rodrigue(laydownV, 1, laydownR, inserts[i]);
                }

                //主切削刃近k点到远k点的单位向量
                Vector3 mainCutEdgeO;
                if (isTf)
                {
                    //逆时针绘制时，对于侧切时的近k点到远k点的单位向量，是上表面第一点到第二点的单位向量
                    mainCutEdgeO = Pus.UnitVector(inserts[InsertShape], inserts[InsertShape + 1]);
                }
                else
                {
                    //逆时针绘制时，对于端切时的近k点到远k点的单位向量，是上表面第一点到最后一个点的单位向量
                    mainCutEdgeO = Pus.UnitVector(inserts[InsertShape], inserts[InsertShape * 2 - 1]);
                }
                //lambdasMaker
                Vector3 lambdasMkr = Pus.Rodrigue(new Vector3(0, 1, 0), 1, pi / 2, mainCutEdgeO);
                //绕lambdasMkr旋转lambdas
                for (int i = 0; i < inserts.Length; i++)
                {
                    inserts[i] = Pus.Rodrigue(lambdasMkr, 1, lambdas, inserts[i]);
                }

                //变化之后的主切削刃单位向量就是产生gammao的向量
                Vector3 gammaoMkr;
                if (isTf)
                {
                    //侧切时，gammaoMkr是主切削刃远k点到近k点的单位向量
                    gammaoMkr = Pus.UnitVector(inserts[InsertShape + 1], inserts[InsertShape]);
                }
                else
                {
                    //端切时，gammaoMkr是主切削刃近k点到远k点的单位向量
                    gammaoMkr = Pus.UnitVector(inserts[InsertShape], inserts[InsertShape * 2 - 1]);
                }
                //创建gammao
                if (o7n)
                {
                    //前角γo,把它转换成法前角
                    for (int i = 0; i < inserts.Length; i++)
                    {
                        inserts[i] = Pus.Rodrigue(gammaoMkr, 1, Math.Atan(Math.Cos(lambdas) * Math.Tan(gammao)), inserts[i]);
                    }
                }
                else
                {
                    //旋转的是法前角γn
                    for (int i = 0; i < inserts.Length; i++)
                    {
                        inserts[i] = Pus.Rodrigue(gammaoMkr, 1, gammao, inserts[i]);
                    }
                }
                //立正
                for (int i = 0; i < inserts.Length; i++)
                {
                    inserts[i] = Pus.Rodrigue(laydownV, 1, -laydownR, inserts[i]);
                }

                return inserts;
            }
        }
        public Vector3[] Shank
        {

            get {
                Vector3[] s = new Vector3[8];
                s[4] = new Vector3(0 + l1, 0 + f - b, 0);
                s[5] = new Vector3(s[4].X, s[4].Y + b, s[4].Z);
                s[6] = new Vector3(0 - lfa + l2, s[5].Y, s[5].Z);
                s[7] = new Vector3(s[6].X, s[4].Y, s[6].Z);
                s[0] = Pus.ToV3(s[4], s[4].Z - h2);
                s[1] = Pus.ToV3(s[5], s[5].Z - h2);
                s[2] = Pus.ToV3(s[6], s[6].Z - h2);
                s[3] = Pus.ToV3(s[7], s[7].Z - h2);
                return s;
            }
        }
        #endregion

        public static EntityObject RoundInsert(double radius,double thetaR)
        {
            if (thetaR == 0)
            {
                Circle circle = new Circle(new Vector2(0, 0), radius);
                return circle;
            }
            else
            {
                Ellipse ellipse = new Ellipse(new Vector2(0, 0), radius * Math.Cos(thetaR) * 2, radius * 2);
                return ellipse;
            }


        }

    }
}
